function entities() {
	function openWindow(id) {
		var width  = 600;
		var height = Ext.isIE ? 420 : 430;
		
		window.open('/entities/' + (id ? id + '/edit' : 'new'), (id ? 'winEntity' + id : '_blank'), 'height=' + height + ',width=' + width + ',left=' + (screen.availWidth - width) / 2 + ',top=' + (screen.availHeight - height) / 2);
	}
	
	if(!Wol.entity) {
		applyLocaleForEntities();
		
		Wol.entity.URL = 'entities/';
		Wol.entity.EntityGridPanel = Ext.extend(Ext.ux.PagingGridPanel, {
			initComponent: function() {
				var grid = this;
				var type = this.type || 'Entity';
				
				var sm = new Ext.grid.CheckboxSelectionModel({
					listeners: {
						selectionchange: function() {
							Ext.getCmp('btn-' + type + '-77').setDisabled(this.getCount() != 1);
							Ext.getCmp('btn-' + type + '-82').setDisabled(!this.getCount());
						}
					}
				});
				
				Wol.entity.EntityGridPanel.superclass.initComponent.call(Ext.apply(this, {
					cm: Ext.apply(new Ext.grid.ColumnModel([sm, {
							dataIndex: 'type',
							header: Wol.entity.FIELDS.type,
							hidden: !this.view,
							renderer: function(val) { return eval('Wol.entity.TYPES.' + val.toLowerCase())[0]; }
						},
						{ dataIndex: 'name', header:Wol.entity.FIELDS.name }, {
							dataIndex: 'url',
							header: Wol.entity.FIELDS.url,
							renderer: function(val) { return '<a href="' + val + '">' + val + '</a>'; }
						}, {
							dataIndex: 'email',
							header: Wol.entity.FIELDS.email,
							renderer: function(val) { return '<a href="mailto:' + val + '">' + val + '</a>'; }
						},
						{ dataIndex: 'phone'     , header: Wol.entity.FIELDS.phone },
						{ dataIndex: 'fax'       , header: Wol.entity.FIELDS.fax },
						{ dataIndex: 'address'   , header: Wol.entity.FIELDS.address },
						{ dataIndex: 'zip'       , header: Wol.entity.FIELDS.zip },
						{ dataIndex: 'created_at', header: Wol.FIELDS.created_at, renderer: Ext.util.Format.dateRenderer() },
						{ dataIndex: 'updated_at', header: Wol.FIELDS.updated_at, renderer: Ext.util.Format.dateRenderer() }
					]), { defaultSortable: true }),
					ds: new Ext.data.GroupingStore({
						autoLoad: !this.type,
						baseParams: this.type && { 'entity[type]': type },
						groupField: 'type',
						listeners: {
							loadexception: function() { alert('Exception raised while loading...'); }
						},
						reader: new Ext.data.JsonReader({ id: 'id', root: 'results', totalProperty: 'total' }, [ 'type', 'name', 'url', 'email', 'phone', 'fax', 'address', 'zip', dateColumn('created_at'), dateColumn('updated_at') ]),
						remoteGroup: true,
						remoteSort: true,
						sortInfo: { field: 'name', direction: 'ASC' },
						url: Wol.entity.URL
					}),
					sm: sm,
					keys: {
						alt: true,
						handler: function(key) {
							var button = Ext.getCmp('btn-' + type + '-' + key);
							
							if(!button.disabled) {
								button.handler.call();
							}
						},
						key: 'cmr'
					},
					tbar: [
						button(Wol.entity.BUTTONS.grid.create, function() { openWindow(); }, { iconCls: 'add', id: 'btn-' + type + '-67' }), '-',
						button(Wol.entity.BUTTONS.grid.modify, function() { grid.fireEvent('celldblclick', grid, null, 1); }, { disabled: true, id: 'btn-' + type + '-77' }), '-',
						button(Wol.entity.BUTTONS.grid.remove, function() {
							var count = sm.getCount();
							
							if(confirm('Do you really want to delete these ' + count + ' item(s)?')) {
								Ext.Msg.progress(Ext.form.BasicForm.prototype.waitTitle, Ext.form.Action.Submit.WAIT_MSG, '0 / ' + count);
								
								function remove(index) {
									Ext.Ajax.request({
										method: 'DELETE',
										success: function() {
											Ext.Msg.updateProgress(++ index / count, index + ' / ' + count);
											
											if(index < count) {
												remove(index);
											} else {
												hideActiveWindow();
												
												tab.items.each(function(item) {
													if(item.isVisible()) {
														item.getStore().load();
													} else if(item.rendered) {
														item.on('activate', Ext.ux.PagingGridPanel.load, this, { single: true });
													}
												});
											}
										},
										url: Wol.entity.URL + sm.getSelections()[index].id
									});
								}
								
								remove(0);
							}
						}, { disabled: true, iconCls: 'remove', id: 'btn-' + type + '-82' })
					]
				}));
				
				if(this.type) {
					this.on('activate', Ext.ux.PagingGridPanel.load, this, { single: true });
				}
			},
			listeners: {
				celldblclick: function(grid, rowIndex, columnIndex) {
					if(columnIndex) {
						openWindow(this.getSelectionModel().getSelected().id);
					}
				}
			}
		});
		
		Ext.reg('entitygrid', Wol.entity.EntityGridPanel);
	}
	
	var tab = center.add({
		defaultType: 'entitygrid',
		id: 'tab-entities',
		items: [
			{ title: Wol.entity.TITLES.grid, view: new Ext.grid.GroupingView() },
			{ title: Wol.entity.TYPES.institution[0], type: Wol.entity.TYPES.institution[1] },
			{ title: Wol.entity.TYPES.individual [0], type: Wol.entity.TYPES.individual [1] }
		],
		title: Wol.entity.TITLES.tab,
		xtype: 'tabpanel'
	});
}
